#pragma once
#ifndef TM_BASE_TYPES_H_
#define TM_BASE_TYPES_H_

#include <cuda_runtime.h>
#include <float.h>

#define BYTES_TO_KB(x) ((double) x / 1024.0)
#define BYTES_TO_MB(x) ((double) BYTES_TO_KB(x) / 1024.0)

#define BLOCK_SIZE 16
#define FULL_BLOCK_SIZE (BLOCK_SIZE * BLOCK_SIZE)
#define GRID_REDUCTION 16
#define REDUCTION_BLOCK_SIZE (FULL_BLOCK_SIZE * GRID_REDUCTION)

#define EXPAND_TO_BLOCK_SIZE(x) ( (x) % BLOCK_SIZE == 0 ? (x) : ((x) - (x) % BLOCK_SIZE + BLOCK_SIZE) )
#define EXPAND_TO_FULL_BLOCK_SIZE(x) ( (x) % (FULL_BLOCK_SIZE) == 0 ? (x) : ((x) - (x) % (FULL_BLOCK_SIZE) + (FULL_BLOCK_SIZE)) )
#define EXPAND_TO_REDUCTION_BLOCK_SIZE(x) ( (x) % (REDUCTION_BLOCK_SIZE) == 0 ? (x) : ((x) - (x) % (REDUCTION_BLOCK_SIZE) + (REDUCTION_BLOCK_SIZE)) )

#define CV_TIME(t) (((double) getTickCount() - (t)) / getTickFrequency())

namespace recognition {

template < typename T >
class IBuilder {
public:
	virtual ~IBuilder() {}
	virtual T build() = 0;
};

// Matrices are stored in row-major order:
// M(row, col) = *(M.elements + row * M.width + col)
template <typename T>
struct Matrix {
	__host__ __device__ Matrix(int _height = 0, int _width = 0) : height(_height), width(_width), elements(NULL) {}

    int width;
    int height;
    T* elements;
};

typedef Matrix<unsigned char>	Matrix2uchar;
typedef Matrix<float>			Matrix2f;
typedef Matrix<double>			Matrix2d;

typedef struct Point2D {
	__host__ __device__ Point2D(int _x = 0, int _y = 0) : x(_x), y(_y) {}
	int x, y;
} Point2D;

template <typename T>
struct BoundsWithStep {
	__host__ __device__ BoundsWithStep(T _step = 0, T _min = 0, T _max = 0) : step(_step), min(_min), max(_max) {}
	T step;
	T min;
	T max;
};

}	// namespace recognition

#endif	// TM_BASE_TYPES_H_
